﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using DiscoveryLogic.Common.Utilities;
using DiscoveryLogic.DataViz.NetworkDiagram.Layouts;
using DiscoveryLogic.DataViz.NetworkDiagram.LinkerControls;
using DiscoveryLogic.DataViz.NetworkDiagram.Measures;
using DiscoveryLogic.DataViz.NetworkDiagram.NetworkData;
using DiscoveryLogic.DataViz.NetworkDiagram.QueryControls;
using DiscoveryLogic.DataViz.NetworkDiagram.Rules;
using DiscoveryLogic.WindowsUserControl;
using DiscoveryLogic.WindowsUserControl.UIUpdateWrapper;
using Divelements.Navisight;
using TD.SandDock;
using EntityType=DiscoveryLogic.DataViz.NetworkDiagram.NetworkData.EntityType;

namespace DiscoveryLogic.DataViz.NetworkDiagram
{
    /// <summary>
    /// 
    /// </summary>
    public partial class Main : Form
    {
        private IGraphLayout _Render;
        private Dictionary<TabbedDocument, PictureBox> _OpenedPicBoxes=new Dictionary<TabbedDocument, PictureBox>();
        private Dictionary<TabbedDocument, Graph> _OpenedGraphs=new Dictionary<TabbedDocument, Graph>();
        private List<object> _Selection;
        private Point _ROIFinish = Point.Empty;
        private Point _ROIStart = Point.Empty;

        #region init
        /// <summary>
        /// 
        /// </summary>
        public Main()
        {
            InitializeComponent();
            this.Closing += new CancelEventHandler(Main_Closing);
        }

        void Main_Closing(object sender, CancelEventArgs e)
        {
            if(this._Render !=null && (!this._Render.IsStopped))
                this._Render.StopRender();
        }

        private void Main_Load(object sender, EventArgs e)
        {
            this._Render = new ForceDirectedLayout();

            this.tree_Workspaces.Nodes.Clear();
            TreeNode networkRootTN=new TreeNode("Networks");
            networkRootTN.ImageIndex = 5;
            networkRootTN.SelectedImageIndex = 5;
            this.tree_Workspaces.Nodes.Add(networkRootTN);
            this.PopulateNetworks(networkRootTN);
            TreeNode graphRootTN=new TreeNode("Graphs");
            graphRootTN.ImageIndex = 6;
            graphRootTN.SelectedImageIndex = 6;
            this.tree_Workspaces.Nodes.Add(graphRootTN);
            this.PopulateGraphs(graphRootTN);

            this.tree_Rules.Nodes.Clear();
            TreeNode relationRootTn=new TreeNode("Relation rules");
            relationRootTn.ImageIndex = relationRootTn.SelectedImageIndex = 0;
            this.tree_Rules.Nodes.Add(relationRootTn);
            this.PopulateRelationRules(relationRootTn);
        }

        private void PopulateNetworks(TreeNode parentTN)
        {
            parentTN.Nodes.Clear();
            Dictionary<EntityType, List<Network>> networks= WorkspaceManager.GetAllNetworks();
            if(networks !=null && networks.Count>0)
            {
                foreach(EntityType nodeType in networks.Keys)
                {
                    TreeNode entityRootTN=new TreeNode(nodeType.ToString());
                    entityRootTN.ImageIndex = 0;
                    entityRootTN.SelectedImageIndex = 0;
                    parentTN.Nodes.Add(entityRootTN);
                    List<Network> networksByEntityType = networks[nodeType];
                    foreach(Network network in networksByEntityType)
                    {
                        TreeNode networkTN=new TreeNode(network.NetworkName);
                        switch(nodeType)
                        {
                            case EntityType.Project:
                                networkTN.ImageIndex = 1;
                                networkTN.SelectedImageIndex = 1;
                                break;
                            case EntityType.Persons:
                                networkTN.ImageIndex = 2;
                                networkTN.SelectedImageIndex = 2;
                                break;
                            case EntityType.Publications:
                                networkTN.ImageIndex = 3;
                                networkTN.SelectedImageIndex = 3;
                                break;
                            case EntityType.Organization:
                                networkTN.ImageIndex = 4;
                                networkTN.SelectedImageIndex = 4;
                                break;
                        }
                        networkTN.Tag = network;
                        entityRootTN.Nodes.Add(networkTN);
                    }
                }
            }
        }

        private void PopulateGraphs(TreeNode parentTN)
        {
            parentTN.Nodes.Clear();
            List<string> graphFilePaths = WorkspaceManager.GetAllGraphFiles();
            if(graphFilePaths !=null && graphFilePaths.Count>0)
            {
                foreach(string graphFilePath in graphFilePaths)
                {
                    string graphName = Path.GetFileNameWithoutExtension(graphFilePath);
                    TreeNode graphTN=new TreeNode(graphName);
                    graphTN.ImageIndex = 7;
                    graphTN.SelectedImageIndex = 7;
                    graphTN.Tag = graphFilePath;
                    parentTN.Nodes.Add(graphTN);
                }
            }

        }

        private void PopulateRelationRules(TreeNode relationRootTN)
        {
            List<EntityRelationRule> rules = RuleManager.GetAllEntityRelationRules();
            if(rules !=null && rules.Count>0)
            {
                foreach(EntityRelationRule rule in rules)
                {
                    TreeNode ruleTn=new TreeNode(rule.RuleName);
                    ruleTn.ImageIndex = ruleTn.SelectedImageIndex = 1;
                    ruleTn.Tag = rule;
                    relationRootTN.Nodes.Add(ruleTn);
                }
            }
        }
        #endregion

        #region new network
        private void newToolStripButton_Click(object sender, EventArgs e)
        {
            NewNetworkData newNetworkForm=new NewNetworkData();
            newNetworkForm.NetworkCreated += new OnNetworkCreated(newNetworkForm_NetworkCreated);
            newNetworkForm.Show(this);
        }

        void newNetworkForm_NetworkCreated(Network net)
        {
            TreeNode networkTN = new TreeNode(net.NetworkName);
            networkTN.Tag = net;
            switch(net.EntityType)
            {
                case EntityType.Project:
                    networkTN.ImageIndex = 1;
                    networkTN.SelectedImageIndex = 1;
                    break;
                case EntityType.Persons:
                    networkTN.ImageIndex = 2;
                    networkTN.SelectedImageIndex = 2;
                    break;
                case EntityType.Publications:
                    networkTN.ImageIndex = 3;
                    networkTN.SelectedImageIndex = 3;
                    break;
                case EntityType.Organization:
                    networkTN.ImageIndex = 4;
                    networkTN.SelectedImageIndex = 4;
                    break;
            }
            TreeNode networkRootTN = this.tree_Workspaces.Nodes[0];
            TreeNode entityTypeRootTN = null;
            foreach(TreeNode typeRootTn in networkRootTN.Nodes)
            {
                if(typeRootTn.Text==net.EntityType.ToString())
                {
                    entityTypeRootTN = typeRootTn;
                    break;
                }
            }
            if (entityTypeRootTN != null)
                entityTypeRootTN.Nodes.Add(networkTN);
            else
                networkRootTN.Nodes.Add(networkTN);
            Graph g = new Graph();
            g.FieldStatsUpdated +=new Graph.OnFieldStatsUpdated(_ActiveGraph_FieldStatsUpdated);
            g.GraphMeasureUpdated += new Graph.OnGraphMeasureUpdated(g_GraphMeasureUpdated);
            PictureBox activePicbox = this.AddGraph(g);
            g.InitGraph(net);
            this.RenderGraph(activePicbox.Size, g);
        }
        #endregion

        #region active picbox and graph
        /// <summary>
        /// 
        /// </summary>
        public Graph ActiveGraph
        {
            get
            {
                TabbedDocument tabbedDoc = this.sandDockManager1.ActiveTabbedDocument as TabbedDocument;
                if (tabbedDoc != null && this._OpenedPicBoxes.ContainsKey(tabbedDoc) &&
                    this._OpenedGraphs.ContainsKey(tabbedDoc))
                {
                    return this._OpenedGraphs[tabbedDoc];
                }
                return null;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        public PictureBox ActivePictureBox
        {
            get
            {
                TabbedDocument tabbedDoc = this.sandDockManager1.ActiveTabbedDocument as TabbedDocument;
                if (tabbedDoc != null && this._OpenedPicBoxes.ContainsKey(tabbedDoc) &&
                    this._OpenedGraphs.ContainsKey(tabbedDoc))
                {
                    return this._OpenedPicBoxes[tabbedDoc];
                }
                return null;
            }
        }
        #endregion

        #region graph tab

        private void sandDockManager1_DockControlActivated(object sender, DockControlEventArgs e)
        {
            if(e.DockControl is TabbedDocument)
            {
                TabbedDocument activeTab = e.DockControl as TabbedDocument;
                if (activeTab != this.sandDockManager1.ActiveTabbedDocument)
                {
                    if (activeTab != null && this._OpenedPicBoxes.ContainsKey(activeTab) &&
                        this._OpenedGraphs.ContainsKey(activeTab))
                    {
                        PictureBox activePicBox = this.sandDockManager1.ActiveTabbedDocument.Controls[0] as PictureBox;
                        //activePicBox.MouseDown += new MouseEventHandler(picBox_MouseDown);
                        //activePicBox.MouseUp += new MouseEventHandler(_ActivePicBox_MouseUp);
                        //activePicBox.SizeChanged += new EventHandler(picBox_SizeChanged);
                        //activePicBox.MouseMove += new MouseEventHandler(_ActivePicBox_MouseMove);

                        Graph activeG = this._OpenedGraphs[activeTab];
                        this._Render.Init(activePicBox.Size, activeG);
                        this._Render.GraphUpdated += new OnGraphUpdated(_Render_GraphUpdated);
                        if(!this._Render.IsStopped)
                            this._Render.StopRender();
                        this._Render.StartRender(true);
                    }
                }
            }
        }

        private PictureBox AddGraph(Graph g)
        {
            TD.SandDock.DocumentContainer docContainer = new TD.SandDock.DocumentContainer();
            this.Controls.Add(docContainer);
            
            PictureBox activePicBox = new PictureBox();
            TD.SandDock.TabbedDocument tabbedDoc = new TD.SandDock.TabbedDocument(this.sandDockManager1, docContainer, "Graph");
            tabbedDoc.Open();
            tabbedDoc.Controls.Clear();
            tabbedDoc.Controls.Add(activePicBox);
            tabbedDoc.Closing += new TD.SandDock.DockControlClosingEventHandler(tabbedDoc_Closing);
            tabbedDoc.Closed += new EventHandler(tabbedDoc_Closed);
            activePicBox.Dock = DockStyle.Fill;
            activePicBox.MouseDown += new MouseEventHandler(picBox_MouseDown);
            activePicBox.MouseUp += new MouseEventHandler(_ActivePicBox_MouseUp);
            activePicBox.SizeChanged += new EventHandler(picBox_SizeChanged);
            activePicBox.MouseMove += new MouseEventHandler(_ActivePicBox_MouseMove);

            if(this._OpenedPicBoxes==null)
                this._OpenedPicBoxes=new Dictionary<TabbedDocument, PictureBox>();
            this._OpenedPicBoxes.Add(tabbedDoc, activePicBox);

            if (this._OpenedGraphs == null)
                this._OpenedGraphs = new Dictionary<TabbedDocument, Graph>();
            this._OpenedGraphs.Add(tabbedDoc, g);
            return activePicBox;
        }

        private void RenderGraph(Size picboxSize, Graph g)
        {
            this._Render.Init(picboxSize, g);
            this.PopulateLinkages(g);
            this._Render.GraphUpdated += new OnGraphUpdated(_Render_GraphUpdated);
            if (!this._Render.IsStopped)
                this._Render.StopRender();
            this._Render.StartRender(true);
        }

        void tabbedDoc_Closed(object sender, EventArgs e)
        {
            if (this.sandDockManager1.ActiveTabbedDocument != null)
            {
                TabbedDocument activeTab = this.sandDockManager1.ActiveTabbedDocument as TabbedDocument;
                if (activeTab != null && this._OpenedPicBoxes.ContainsKey(activeTab) &&
                    this._OpenedGraphs.ContainsKey(activeTab))
                {
                    PictureBox activePicBox = this.sandDockManager1.ActiveTabbedDocument.Controls[0] as PictureBox;
                    //activePicBox.MouseDown += new MouseEventHandler(picBox_MouseDown);
                    //activePicBox.MouseUp += new MouseEventHandler(_ActivePicBox_MouseUp);
                    //activePicBox.SizeChanged += new EventHandler(picBox_SizeChanged);
                    //activePicBox.MouseMove += new MouseEventHandler(_ActivePicBox_MouseMove);

                    Graph activeG = this._OpenedGraphs[activeTab];
                    this._Render.Init(activePicBox.Size, activeG);
                    this._Render.GraphUpdated += new OnGraphUpdated(_Render_GraphUpdated);
                    if (!this._Render.IsStopped)
                        this._Render.StopRender();
                    this._Render.StartRender(true);
                }
            }
        }

        void tabbedDoc_Closing(object sender, TD.SandDock.DockControlClosingEventArgs e)
        {
            TabbedDocument closingTab = sender as TabbedDocument;
            if(closingTab !=null)
            {
                if (this._Render != null && (!this._Render.IsStopped))
                    this._Render.StopRender();

                if(this.sandDockManager1.ActiveTabbedDocument==closingTab)
                {
                    
                }
                if (this._OpenedPicBoxes != null && this._OpenedPicBoxes.ContainsKey(closingTab))
                {
                    PictureBox activePicBox = this._OpenedPicBoxes[closingTab];
                    activePicBox.MouseDown -= new MouseEventHandler(picBox_MouseDown);
                    activePicBox.MouseUp -= new MouseEventHandler(_ActivePicBox_MouseUp);
                    activePicBox.SizeChanged -= new EventHandler(picBox_SizeChanged);
                    activePicBox.MouseMove -= new MouseEventHandler(_ActivePicBox_MouseMove);

                    this._OpenedPicBoxes.Remove(closingTab);
                }
                if (this._OpenedGraphs != null && this._OpenedGraphs.ContainsKey(closingTab))
                {
                    this._OpenedGraphs.Remove(closingTab);
                }
            }
        }

        void _ActiveGraph_FieldStatsUpdated(Dictionary<string, Dictionary<string, FieldStat>> fieldStatsByNetwork)
        {
            this.dock_Query.Controls.Clear();
            NavigationBar navibarQuery = new NavigationBar();
            this.dock_Query.Controls.Add(navibarQuery);
            navibarQuery.Dock = DockStyle.Fill;
            if (this.sandDockManager1.ActiveTabbedDocument != null)
            {
                TabbedDocument tabbedDoc = this.sandDockManager1.ActiveTabbedDocument as TabbedDocument;
                if (tabbedDoc != null && this._OpenedPicBoxes.ContainsKey(tabbedDoc) &&
                    this._OpenedGraphs.ContainsKey(tabbedDoc))
                {
                    Graph activeGraph = this._OpenedGraphs[tabbedDoc];
                    if (fieldStatsByNetwork != null && fieldStatsByNetwork.Count > 0)
                    {
                        foreach (string networkName in fieldStatsByNetwork.Keys)
                        {
                            Dictionary<string, FieldStat> fieldStats = fieldStatsByNetwork[networkName];
                            NavigationCategory category = new NavigationCategory();
                            category.Text = networkName;
                            category.Image = Properties.Resources.NewSearchFolder;
                            navibarQuery.Controls.Add(category);
                            category.Dock = DockStyle.Fill;
                            ObjectQueryContainer queryContainer = new ObjectQueryContainer(networkName, fieldStats);
                            category.Controls.Add(queryContainer);
                            queryContainer.Dock = DockStyle.Fill;
                            queryContainer.FieldFilterUpdated += new OnFieldFilterUpdated(queryContainer_FieldFilterUpdated);
                        }

                        List<LinkDataObject> linkDOs=new List<LinkDataObject>();
                        foreach(Edge e in activeGraph.Edges.Values)
                        {
                            if(e.Tag !=null)
                            {
                                linkDOs.Add(e.Tag);
                            }
                        }
                        NavigationCategory categoryLink = new NavigationCategory();
                        categoryLink.Text = "Linkage";
                        categoryLink.Image = Properties.Resources.NewSearchFolder;
                        navibarQuery.Controls.Add(categoryLink);
                        categoryLink.Dock = DockStyle.Fill;
                        List<Network> networks=new List<Network>();
                        networks.AddRange(activeGraph.Networks.Values);
                        LinkageFilter linkageFilter = new LinkageFilter(networks, linkDOs);
                        categoryLink.Controls.Add(linkageFilter);
                        linkageFilter.Dock = DockStyle.Fill;
                        linkageFilter.LinkageFilterUpdated += new LinkageFilter.OnLinkageFilterUpdated(linkageFilter_LinkageFilterUpdated);
                    }
                }
            }
        }

        void _ActivePicBox_MouseUp(object sender, MouseEventArgs e)
        {
            if(this.sandDockManager1.ActiveTabbedDocument !=null)
            {
                TabbedDocument tabbedDoc = this.sandDockManager1.ActiveTabbedDocument as TabbedDocument;
                if(tabbedDoc !=null && this._OpenedPicBoxes.ContainsKey(tabbedDoc) && 
                    this._OpenedGraphs.ContainsKey(tabbedDoc))
                {
                    Graph activeGraph = this._OpenedGraphs[tabbedDoc];
                    if (Keyboard.IsKeyPressed(VirtualKeyStates.VK_CONTROL) && this._ROIStart != Point.Empty && this._ROIFinish != Point.Empty)
                    {
                        Point start = new Point(
                            Math.Min(this._ROIStart.X, this._ROIFinish.X), Math.Min(this._ROIStart.Y, this._ROIFinish.Y));
                        int w = Math.Abs(this._ROIStart.X - this._ROIFinish.X);
                        int h = Math.Abs(this._ROIStart.Y - this._ROIFinish.Y);
                        this._Render.Select(new RectangleF(start.X, start.Y, w, h));
                        if (this._Render.SelectedVertices != null && this._Render.SelectedVertices.Count > 0)
                        {
                            this._Selection = new List<object>();
                            List<string> pkVals = new List<string>();
                            string networkName = string.Empty;
                            foreach (Vertice v in this._Render.SelectedVertices)
                            {
                                this._Selection.Add(v);
                                pkVals.Add(v.PkValue);
                                networkName = v.NetworkName;
                            }
                            Network net = activeGraph.Networks[networkName];
                            DataTable dt = net.SelectByKey(pkVals);
                            this.dv_Selection.DataSource = dt;
                            this.dv_Selection.Refresh();
                        }
                        else
                        {
                            this._Selection = new List<object>();
                            this.dv_Selection.DataSource = null;
                            this.dv_Selection.Refresh();
                        }
                    }
                }
            }

            this._ROIStart = Point.Empty;
            this._ROIFinish = Point.Empty;
        }

        void _ActivePicBox_MouseMove(object sender, MouseEventArgs e)
        {
            if (Keyboard.IsKeyPressed(VirtualKeyStates.VK_CONTROL) && this._ROIStart != Point.Empty)
            {
                this._ROIFinish=new Point(e.X,e.Y);
            }
            else if(e.Button==MouseButtons.Left)
            {
                if (this._Selection != null && this._Selection.Count == 1)
                {
                    if (this._Selection[0].GetType() == typeof (Vertice))
                    {
                        Vertice selectedV = (Vertice) this._Selection[0];
                        this._Render.DragVertice(selectedV, new PointF(e.X, e.Y));
                    }
                }
            }
        }

        void picBox_SizeChanged(object sender, EventArgs e)
        {
            TabbedDocument tabbedDoc = this.sandDockManager1.ActiveTabbedDocument as TabbedDocument;
            if (tabbedDoc != null && this._OpenedPicBoxes.ContainsKey(tabbedDoc) &&
                this._OpenedGraphs.ContainsKey(tabbedDoc))
            {
                PictureBox activePicBox = this._OpenedPicBoxes[tabbedDoc];
                this._Render.GraphSize = activePicBox.Size;
                if (!this._Render.IsStopped)
                    this._Render.StopRender();
                this._Render.StartRender(true);
            }
        }

        void picBox_MouseDown(object sender, MouseEventArgs e)
        {
            Point pos= new Point(e.X, e.Y);
            if (Keyboard.IsKeyPressed(VirtualKeyStates.VK_CONTROL))
            {
                this._ROIStart = pos;
                this._ROIFinish = Point.Empty;
            }
            else
            {
                this._ROIStart = Point.Empty;
                this._ROIFinish = Point.Empty;
                Vertice selectedV = this._Render.SelectVertice(pos);
                TabbedDocument tabbedDoc = this.sandDockManager1.ActiveTabbedDocument as TabbedDocument;
                if (tabbedDoc != null && this._OpenedPicBoxes.ContainsKey(tabbedDoc) &&
                    this._OpenedGraphs.ContainsKey(tabbedDoc))
                {
                    Graph activeGraph = this._OpenedGraphs[tabbedDoc];
                    if (selectedV != null)
                    {
                        this._Selection = new List<object>();
                        this._Selection.Add(selectedV);
                        Network net = activeGraph.Networks[selectedV.NetworkName];
                        List<string> pkVals = new List<string>();
                        pkVals.Add(selectedV.PkValue);
                        DataTable dtResult = net.SelectByKey(pkVals);
                        this.dv_Selection.DataSource = dtResult;
                        this.dv_Selection.Refresh();
                    }
                    else
                    {
                        this._Selection = new List<object>();
                        this.dv_Selection.DataSource = null;
                        this.dv_Selection.Refresh();
                        this._Render.UnSelect();
                    }
                }
            }
        }

        void _Render_GraphUpdated(Image img)
        {
            TabbedDocument tabbedDoc = this.sandDockManager1.ActiveTabbedDocument as TabbedDocument;
            if (tabbedDoc != null && this._OpenedPicBoxes.ContainsKey(tabbedDoc) &&
                this._OpenedGraphs.ContainsKey(tabbedDoc))
            {
                img = this.UpdateGraphWithSelectionROI((Bitmap)img);
                PictureBox activePicBox = this._OpenedPicBoxes[tabbedDoc];
                new PictureBoxUpdator(activePicBox, PictureBoxSizeMode.StretchImage, img);
            }
            
        }

        private Bitmap UpdateGraphWithSelectionROI(Bitmap img)
        {
            if(this._ROIStart !=Point.Empty && this._ROIFinish !=Point.Empty)
            {
                Graphics g = Graphics.FromImage(img);
                Point from = new Point(
                    Math.Min(this._ROIStart.X, this._ROIFinish.X),
                    Math.Min(this._ROIStart.Y, this._ROIFinish.Y));
                int w = Math.Abs(this._ROIStart.X - this._ROIFinish.X);
                int h = Math.Abs(this._ROIStart.Y - this._ROIFinish.Y);
                Pen roiPen = new Pen(Color.Gray, 1);
                g.DrawRectangle(roiPen, from.X, from.Y, w, h);
                g.Dispose();
                return img;
            }
            else
                return img;
        }
        #endregion

        #region linker
        private void addLinkerToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (this.ActiveGraph != null)
            {
                AddLinker addLinkerForm = new AddLinker(this.ActiveGraph);
                addLinkerForm.LinkerAdded += new AddLinker.OnLinkerAdded(addLinkerForm_LinkerAdded);
                addLinkerForm.Show(this);
            }
        }

        private void addLinkerToolStripMenuItem1_Click(object sender, EventArgs e)
        {
            if(this.ActivePictureBox==null || this.ActiveGraph==null)
                return;

            AddLinker addLinkerForm = new AddLinker(this.ActiveGraph);
            addLinkerForm.LinkerAdded += new AddLinker.OnLinkerAdded(addLinkerForm_LinkerAdded);
            addLinkerForm.Show(this);
        }

        void addLinkerForm_LinkerAdded(
            string network1, string memberName1, 
            string network2, string memberName2, 
            string linkerTypeName, 
            NetworkLinkBehavior behavior, 
            double attractForce, double repelForce)
        {
            NetworkJoin join = new NetworkJoin();
            
            Network toNet = Network.ReadNetwork(network2);
            join.FromNetworkName = network1;
            join.FromObjMemberName = memberName1;
            join.ToNetworkName = network2;
            join.ToObjMemberName = memberName2;
            join.JoinCalcTypeName = linkerTypeName;
            join.Behavior = behavior;
            join.AttractingForce = attractForce;
            join.RepellingForce = repelForce;
            try
            {
                this.ActiveGraph.JoinNetwork(toNet, join);
                this._Render.Init(this.ActivePictureBox.Size, this.ActiveGraph);
                if (!this._Render.IsStopped)
                    this._Render.StopRender();
                this._Render.StartRender(true);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }
        #endregion

        #region remove
        private void removeNetworkToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if(this.tree_Workspaces.SelectedNode !=null)
            {
                System.Windows.Forms.DialogResult result = MessageBox.Show(
                    "Are you sure to remove network " +
                    this.tree_Workspaces.SelectedNode.Text + "?", "Delete", MessageBoxButtons.YesNo);
                if(result==DialogResult.Yes)
                {
                    WorkspaceManager.DeleteNetwork(this.tree_Workspaces.SelectedNode.Text);
                    this.tree_Workspaces.Nodes.Remove(this.tree_Workspaces.SelectedNode);
                }
            }
        }
        #endregion

        #region display
        private void displayNetworkToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (this.tree_Workspaces.SelectedNode != null)
            {
                string networkName = this.tree_Workspaces.SelectedNode.Text;
                Network network = Network.ReadNetwork(networkName);
                Graph g = new Graph();
                g.FieldStatsUpdated+=new Graph.OnFieldStatsUpdated(_ActiveGraph_FieldStatsUpdated);
                g.GraphMeasureUpdated += new Graph.OnGraphMeasureUpdated(g_GraphMeasureUpdated);
                PictureBox activePicbox = this.AddGraph(g);
                g.InitGraph(network);
                this.RenderGraph(activePicbox.Size, g);
            }
        }

    
        #endregion

        #region viz
        private void applyVisualSettingToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if(this.tree_Workspaces.SelectedNode !=null)
            {
                Network net = Network.ReadNetwork(this.tree_Workspaces.SelectedNode.Text);
                VisualSettings vizSettingForm=new VisualSettings(net.NetworkName, net.VizSetting);
                vizSettingForm.VizSettingUpdated += new VisualSettings.OnVizSettingUpdated(vizSettingForm_VizSettingUpdated);
                vizSettingForm.Show(this);
            }
        }

        void vizSettingForm_VizSettingUpdated(string networkName, NetworkVisualSetting vizSetting)
        {
            Network net = Network.ReadNetwork(networkName);
            net.VizSetting = vizSetting;
            net.Save();
        }
        #endregion

        #region save
        private void saveToolStripButton_Click(object sender, EventArgs e)
        {
            if(this.ActiveGraph!=null)
            {
                SaveFileDialog dlg=new SaveFileDialog();
                dlg.Filter = "Graph files(*.graph)|*.graph|All files(*.*)|*.*";
                string appFolder = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
                appFolder = Path.Combine(appFolder, "Graph Data");
                if (!Directory.Exists(appFolder))
                    Directory.CreateDirectory(appFolder);
                dlg.FileName = Path.Combine(appFolder, "newgraph.graph");
                if(dlg.ShowDialog()==System.Windows.Forms.DialogResult.OK)
                {
                    this.ActiveGraph.Save(dlg.FileName);
                    string graphName = Path.GetFileNameWithoutExtension(dlg.FileName);
                    TreeNode graphRootTN = this.tree_Workspaces.Nodes[1];
                    bool found = false;
                    if(graphRootTN.Nodes.Count>0)
                    {
                        foreach(TreeNode gTn in graphRootTN.Nodes)
                        {
                            if(gTn.Text==graphName)
                            {
                                found = true;
                                break;
                            }
                        }
                    }
                    if(!found)
                    {
                        TreeNode gTNNew = new TreeNode(graphName);
                        gTNNew.Tag = dlg.FileName;
                        gTNNew.ImageIndex = 7;
                        gTNNew.SelectedImageIndex = 7;
                        graphRootTN.Nodes.Add(gTNNew);
                    }
                }
            }
        }
        #endregion

        #region open
        private void openToolStripButton_Click(object sender, EventArgs e)
        {
            OpenFileDialog dlg=new OpenFileDialog();
            dlg.Filter = "Graph files(*.graph)|*.graph|Network files(*.net)|*.net|All files(*.*)|*.*";
            if(dlg.ShowDialog()==System.Windows.Forms.DialogResult.OK)
            {
                
            }
        }
        #endregion

        private void graphMeasuresToolStripMenuItem_Click(object sender, EventArgs e)
        {
            GraphMeasureSettings form=new GraphMeasureSettings();
            form.Show(this);
        }

        #region explore
        
        //void exForm_ObjectExplored(string fromNetworkName, string toNetworkName, NetworkJoin join)
        //{
        //    if(this.ActiveGraph!=null)
        //    {
        //        Network toNet = Network.ReadNetwork(toNetworkName);
        //        try
        //        {
        //            this.ActiveGraph.JoinNetwork(toNet, join);
        //            this._Render.Init(this.ActivePictureBox.Size, this.ActiveGraph);
        //            if (!this._Render.IsStopped)
        //                this._Render.StopRender();
        //            this._Render.StartRender(true);
        //        }
        //        catch (Exception ex)
        //        {
        //            MessageBox.Show(ex.Message);
        //        }
        //    }
        //}
        #endregion

        #region start/stop
        private void btn_Refresh_Click(object sender, EventArgs e)
        {
            if (this.ActiveGraph != null && this._Render != null)
            {
                if (!this._Render.IsStopped)
                    this._Render.StopRender();
                this._Render.StartRender(true);
            }
        }

        private void btn_Stop_Click(object sender, EventArgs e)
        {
            if(this.ActiveGraph!=null && this._Render !=null)
                this._Render.StopRender();
        }
        #endregion

        private void contextMenuStrip1_Opening(object sender, CancelEventArgs e)
        {
            this.contextMenuStrip1.Items.Clear();
            if(this.tree_Workspaces.SelectedNode !=null)
            {
                if(this.tree_Workspaces.SelectedNode.Tag !=null && 
                    this.tree_Workspaces.SelectedNode.Tag is Network)
                {
                    // network actions 
                    ToolStripMenuItem displayNetworkMenuItem = new ToolStripMenuItem("Display network");
                    displayNetworkMenuItem.Click +=new EventHandler(displayNetworkToolStripMenuItem_Click);
                    this.contextMenuStrip1.Items.Add(displayNetworkMenuItem);
                    ToolStripMenuItem addLinkerMenuItem = new ToolStripMenuItem("Add linker (existing network)");
                    addLinkerMenuItem.Click += new EventHandler(addLinkerToolStripMenuItem_Click);
                    this.contextMenuStrip1.Items.Add(addLinkerMenuItem);
                    ToolStripMenuItem ruleMenuItem = new ToolStripMenuItem("Define relations");
                    ruleMenuItem.Click += new EventHandler(ruleDefToolStripMenuItem_Click);
                    this.contextMenuStrip1.Items.Add(ruleMenuItem);
                    ToolStripMenuItem removeNetworkMenuItem = new ToolStripMenuItem("Remove network");
                    removeNetworkMenuItem.Click +=new EventHandler(removeNetworkToolStripMenuItem_Click);
                    this.contextMenuStrip1.Items.Add(removeNetworkMenuItem);
                    ToolStripMenuItem visualMenuItem = new ToolStripMenuItem("Edit visual settings");
                    visualMenuItem.Click +=new EventHandler(applyVisualSettingToolStripMenuItem_Click);
                    this.contextMenuStrip1.Items.Add(visualMenuItem);
                    ToolStripMenuItem exploreMenuItem = new ToolStripMenuItem("Explore");
                    exploreMenuItem.Click += new EventHandler(exploreMenuItem_Click);
                    this.contextMenuStrip1.Items.Add(exploreMenuItem);
                }
                else if(this.tree_Workspaces.SelectedNode !=null && 
                    this.tree_Workspaces.SelectedNode.ImageIndex==7)
                {
                    // Graph actions 
                    ToolStripMenuItem displayGraphMenuItem = new ToolStripMenuItem("Display graph");
                    displayGraphMenuItem.Click += new EventHandler(displayGraphMenuItem_Click);
                    this.contextMenuStrip1.Items.Add(displayGraphMenuItem);
                    ToolStripMenuItem addLinkerMenuItem = new ToolStripMenuItem("Add linker (existing network)");
                    addLinkerMenuItem.Click += new EventHandler(addLinkerToolStripMenuItem_Click);
                    this.contextMenuStrip1.Items.Add(addLinkerMenuItem);
                    ToolStripMenuItem exploreMenuItem = new ToolStripMenuItem("Explore");
                    exploreMenuItem.Click += new EventHandler(ruleDefToolStripMenuItem_Click);
                    this.contextMenuStrip1.Items.Add(exploreMenuItem);
                    ToolStripMenuItem removeGraphMenuItem=new ToolStripMenuItem("Remove graph");
                    removeGraphMenuItem.Click += new EventHandler(removeGraphMenuItem_Click);
                    this.contextMenuStrip1.Items.Add(removeGraphMenuItem);
                }
            }
        }

     

        void removeGraphMenuItem_Click(object sender, EventArgs e)
        {
            if(this.tree_Workspaces.SelectedNode !=null)
            {
                TreeNode graphTN = this.tree_Workspaces.SelectedNode;
                string graphName = graphTN.Text;
                WorkspaceManager.RemoveGraph(graphName);
                graphTN.Remove();
            }
        }

        void displayGraphMenuItem_Click(object sender, EventArgs e)
        {
            TreeNode graphTN = this.tree_Workspaces.SelectedNode;
            string graphFilePath = graphTN.Tag as string;
            List<Vertice> vertices=new List<Vertice>();
            List<Edge> edges=new List<Edge>();
            Dictionary<string, Network> networks=new Dictionary<string, Network>();
            List<NetworkJoin> joins=new List<NetworkJoin>();
            Graph.Read(graphFilePath, ref vertices, ref edges, ref networks, ref joins);
            Graph g =new Graph();
            g.FieldStatsUpdated += new Graph.OnFieldStatsUpdated(_ActiveGraph_FieldStatsUpdated);
            g.GraphMeasureUpdated += new Graph.OnGraphMeasureUpdated(g_GraphMeasureUpdated);
            PictureBox activePicbox = this.AddGraph(g);
            g.Networks = networks;
            g.Joins = joins;
            g.InitializeGraphObjects(vertices, edges);
            this.RenderGraph(activePicbox.Size, g);

            /*
            TD.SandDock.DocumentContainer docContainer = new TD.SandDock.DocumentContainer();
            this.Controls.Add(docContainer);

            PictureBox activePicBox = new PictureBox();
            TD.SandDock.TabbedDocument tabbedDoc = new TD.SandDock.TabbedDocument(this.sandDockManager1, docContainer, "Graph");
            tabbedDoc.Open();
            tabbedDoc.Controls.Clear();
            tabbedDoc.Controls.Add(activePicBox);
            tabbedDoc.Closing += new TD.SandDock.DockControlClosingEventHandler(tabbedDoc_Closing);
            tabbedDoc.Closed += new EventHandler(tabbedDoc_Closed);
            activePicBox.Dock = DockStyle.Fill;
            activePicBox.MouseDown += new MouseEventHandler(picBox_MouseDown);
            activePicBox.MouseUp += new MouseEventHandler(_ActivePicBox_MouseUp);
            activePicBox.SizeChanged += new EventHandler(picBox_SizeChanged);
            activePicBox.MouseMove += new MouseEventHandler(_ActivePicBox_MouseMove);

            if (this._OpenedPicBoxes == null)
                this._OpenedPicBoxes = new Dictionary<TabbedDocument, PictureBox>();
            this._OpenedPicBoxes.Add(tabbedDoc, activePicBox);

            if (this._OpenedGraphs == null)
                this._OpenedGraphs = new Dictionary<TabbedDocument, Graph>();
            this._OpenedGraphs.Add(tabbedDoc, g);

            g.InitializeGraphObjects(vertices, edges);
            this._Render.Init(activePicBox.Size, g);
            this.PopulateLinkages(g);
            this.DisplayGraphProperty(g);
            this._Render.GraphUpdated += new OnGraphUpdated(_Render_GraphUpdated);
            if (!this._Render.IsStopped)
                this._Render.StopRender();
            this._Render.StartRender(true);
            */
        }

        #region linkage 
        private void PopulateLinkages(Graph g)
        {
            DataTable dtLinkage=new DataTable();
            dtLinkage.Columns.Add("From object");
            dtLinkage.Columns.Add("To object");
            dtLinkage.Columns.Add("From field");
            dtLinkage.Columns.Add("To field");
            dtLinkage.Columns.Add("Distance", typeof (double));
            Dictionary<Guid, string> vNetworkAssociation=new Dictionary<Guid, string>();
            foreach(Vertice v in g.Vertices.Values)
            {
                vNetworkAssociation.Add(v.ID, v.NetworkName);
            }
            foreach(Edge e in g.Edges.Values)
            {
                LinkDataObject lk = e.Tag;
                if (lk != null)
                {
                    DataRow drLink = dtLinkage.NewRow();
                    Vertice fromV = g.Vertices[e.VerticeID1];
                    Vertice toV = g.Vertices[e.VerticeID2];
                    Network fromNetwork = g.Networks[fromV.NetworkName];
                    Network toNetwork = g.Networks[toV.NetworkName];
                    drLink[0] = string.Format("{0} ({1})", fromV.PkValue, fromNetwork.NetData.GetType().Name);
                    drLink[1] = string.Format("{0} ({1})", toV.PkValue, toNetwork.NetData.GetType().Name);
                    drLink[2] = string.Format("{0} ({1})", lk.FromKey, lk.FromMemberName);
                    drLink[3] = string.Format("{0} ({1})", lk.ToKey, lk.ToMemberName);
                    drLink[4] = lk.Distance;
                    dtLinkage.Rows.Add(drLink);
                }
            }

            this.lv_Links.Items.Clear();
            this.lv_Links.Columns.Clear();

            foreach(DataColumn col in dtLinkage.Columns)
            {
                this.lv_Links.Columns.Add(col.ColumnName);
            }
            foreach(DataRow dr in dtLinkage.Rows)
            {
                ListViewItem lvItem = new ListViewItem(dr[0].ToString());
                for(int k=1;k<dtLinkage.Columns.Count;k++)
                {
                    lvItem.SubItems.Add(dr[k].ToString());
                }
                this.lv_Links.Items.Add(lvItem);
            }
            this.lv_Links.Refresh();
        }
        #endregion

        #region graph property grid
        void g_GraphMeasureUpdated(Graph g)
        {
            this.DisplayGraphProperty(g);
        }

        private void DisplayGraphProperty(Graph g)
        {
            GraphMetaData metaData=new GraphMetaData();
            metaData.GraphName = string.Empty;
            metaData.Density = (double) g.Edges.Count/g.Vertices.Count;
            metaData.EdgeCount = g.Edges.Count;
            List<EntityType> entityTypes=new List<EntityType>();
            List<LinkType> linkTypes = new List<LinkType>();
            List<string> networkNames=new List<string>();
            foreach(Network network in g.Networks.Values)
            {
                if(!entityTypes.Contains(network.EntityType))
                    entityTypes.Add(network.EntityType);
                if(!linkTypes.Contains(network.RelationType))
                    linkTypes.Add(network.RelationType);
                if(!networkNames.Contains(network.NetworkName))
                    networkNames.Add(network.NetworkName);
            }
            metaData.IncludedEntityTypes=new EntityType[entityTypes.Count];
            entityTypes.CopyTo(metaData.IncludedEntityTypes,0);
            metaData.IncludedLinkTypes=new LinkType[linkTypes.Count];
            linkTypes.CopyTo(metaData.IncludedLinkTypes,0);
            int maxInDegree = 0;
            int maxOutDegree = 0;
            foreach(Vertice v in g.Vertices.Values)
            {
                if (v.OutDegree > maxOutDegree)
                {
                    maxOutDegree = v.OutDegree;
                    metaData.MostExpansiveVerticeName = v.Label;
                }
                if(v.InDegree > maxInDegree)
                {
                    maxInDegree = v.InDegree;
                    metaData.MostPopularVerticeName = v.Label;
                }
            }
            metaData.NetworkNames=new string[networkNames.Count];
            networkNames.CopyTo(metaData.NetworkNames,0);
            metaData.VerticeCount = g.Vertices.Count;
            List<double> distances=new List<double>();
            foreach(Edge e in g.Edges.Values)
            {
                distances.Add((double)e.Length);
            }
            metaData.MaxDistance = StatsUtil.GetMax(distances);
            metaData.MinDistance = StatsUtil.GetMin(distances);
            metaData.AvgDistance = StatsUtil.GetAverage(distances);
            metaData.DistanceSD = StatsUtil.GetStandardDeviation(distances);
            this.propertyGrid1.SelectedObject = metaData;
        }
        #endregion

        #region show label and distances
        private void ck_ShowVerticeLabel_CheckedChanged(object sender, EventArgs e)
        {
            this._Render.ShowVerticeLabels = this.ck_ShowVerticeLabel.Checked;
            if (this._Render.IsStopped)
                this._Render.UpdateImage();
        }

        private void ck_ShowDistance_CheckedChanged(object sender, EventArgs e)
        {
            this._Render.ShowEdgeDistances = this.ck_ShowDistance.Checked;
            if (this._Render.IsStopped)
                this._Render.UpdateImage();
        }
        #endregion

        #region selection & filter 
        private void lv_Links_SelectedIndexChanged(object sender, EventArgs e)
        {

        }

        private void dv_Selection_SelectionChanged(object sender, EventArgs e)
        {

        }

        void linkageFilter_LinkageFilterUpdated(List<LinkType> linkTypes, double minDistance, double maxDistance)
        {
            TabbedDocument tabbedDoc = this.sandDockManager1.ActiveTabbedDocument as TabbedDocument;
            if (tabbedDoc != null && this._OpenedPicBoxes.ContainsKey(tabbedDoc) &&
                this._OpenedGraphs.ContainsKey(tabbedDoc))
            {
                Graph activeGraph = this._OpenedGraphs[tabbedDoc];
                List<Guid> selectedEIDs=new List<Guid>();
                foreach(Edge e in activeGraph.Edges.Values)
                {
                    LinkDataObject link = e.Tag;
                    if(link==null)
                        continue;
                    if(linkTypes.Contains(link.RelationType) && 
                        link.Distance >=minDistance && 
                        link.Distance <=maxDistance)
                    {
                        selectedEIDs.Add(e.ID);
                    }
                }

                this._Render.SelectEdges(selectedEIDs);
                if (this._Render.IsStopped)
                    this._Render.UpdateImage();
            }
        }

        void queryContainer_FieldFilterUpdated(string networkName, string fieldName, object min, object max, List<string> inValues)
        {
            TabbedDocument tabbedDoc = this.sandDockManager1.ActiveTabbedDocument as TabbedDocument;
            if (tabbedDoc != null && this._OpenedPicBoxes.ContainsKey(tabbedDoc) &&
                this._OpenedGraphs.ContainsKey(tabbedDoc))
            {
                Graph activeGraph = this._OpenedGraphs[tabbedDoc];
                Network net = activeGraph.Networks[networkName];
                List<string> keysSelected=new List<string>();
                List<Guid> selectedVIDs=new List<Guid>();
                if(inValues !=null && inValues.Count>0)
                {
                    keysSelected = net.GetObjectKeysUsingFieldFilter(fieldName, inValues);
                }
                else if(max !=null && min !=null)
                {
                    keysSelected = net.GetObjectKeysUsingFieldRangeFilter(fieldName, min, max);
                }
                this._Selection=new List<object>();
                if(keysSelected !=null && keysSelected.Count>0)
                {
                    foreach(Vertice v in activeGraph.Vertices.Values)
                    {
                        if(v.NetworkName==networkName && keysSelected.Contains(v.PkValue))
                        {
                            selectedVIDs.Add(v.ID);
                            this._Selection.Add(v);
                        }
                    }
                }

                DataTable dtSelectedNetData = net.SelectByKey(keysSelected);
                this.dv_Selection.DataSource = dtSelectedNetData;
                this.dv_Selection.Refresh();

                this._Render.SelectVertices(selectedVIDs);
                if(this._Render.IsStopped)
                    this._Render.UpdateImage();
            }
        }
        #endregion

        #region rules
        private void openRuleToolStripMenuItem_Click(object sender, EventArgs e)
        {

        }

        private void deleteRuleToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if(this.tree_Rules.SelectedNode !=null && this.tree_Rules.SelectedNode.ImageIndex==1)
            {
                string ruleName = this.tree_Rules.SelectedNode.Text;
                RuleManager.DeleteRule(ruleName);
                this.tree_Rules.SelectedNode.Remove();
            }
        }

        private void ruleDefToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (this.ActiveGraph != null && this._Selection != null &&
                this._Selection.Count > 0 && this._Selection[0].GetType() == typeof(Vertice))
            {
                Vertice v = (Vertice)this._Selection[0];
                Network network = this.ActiveGraph.Networks[v.NetworkName];
                EntityRelationRuleDefinition entityRelationExplorer = new EntityRelationRuleDefinition(network);
                entityRelationExplorer.RelationRuleDefined += new EntityRelationRuleDefinition.OnRelationRuleDefined(entityRelationExplorer_RelationRuleDefined);
                entityRelationExplorer.Show(this);
            }
        }

        void entityRelationExplorer_RelationRuleDefined(DiscoveryLogic.DataViz.NetworkDiagram.Rules.EntityRelationRule rule)
        {
            RuleManager.SaveRule(rule);
            TreeNode relationRootTN = this.tree_Rules.Nodes[0];
            TreeNode ruleTn = new TreeNode(rule.RuleName);
            ruleTn.ImageIndex = ruleTn.SelectedImageIndex = 1;
            ruleTn.Tag = rule;
            relationRootTN.Nodes.Add(ruleTn);
        }

        void exploreMenuItem_Click(object sender, EventArgs e)
        {
            if (this.ActiveGraph != null)
            {
                List<EntityRelationRule> rules = RuleManager.GetAllEntityRelationRules();
                if (rules != null && rules.Count > 0)
                {
                    try
                    {
                        EntityRelationRule rule = rules[0];
                        string[] networkNames = new string[this.ActiveGraph.Networks.Count];
                        this.ActiveGraph.Networks.Keys.CopyTo(networkNames, 0);
                        Network srcNet = this.ActiveGraph.Networks[networkNames[0]];
                        EntityRelationWorker worker = new EntityRelationWorker(rule, srcNet, "Publications");
                        Network newNetwork = worker.ReadRelatedData();
                        NetworkJoin join = new NetworkJoin();
                        this.ActiveGraph.JoinNetwork(newNetwork, join);
                    }
                    catch(Exception ex)
                    {
                        MessageBox.Show(ex.Message);
                    }
                }
            }
        }
        #endregion
    }
}
